package org.jeecg.modules.online.desform.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.es.JeecgElasticsearchTemplate;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.online.desform.constant.WidgetTypes;
import org.jeecg.modules.online.desform.entity.DesignForm;
import org.jeecg.modules.online.desform.entity.DesignFormData;
import org.jeecg.modules.online.desform.util.convert.ConvertItem;
import org.jeecg.modules.online.desform.util.convert.DesformConverter;
import org.jeecg.modules.online.desform.vo.excel.DesformWidgetList;
import org.jeecg.modules.online.desform.vo.widget.DesformOptions;
import org.jeecg.modules.online.desform.vo.widget.DesformWidget;
import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class DesformUtils {

    public static String KEY_SUB_PREFIX = "sub-table-design_";

    /**
     * 递归调用处理所有的组件（包括栅格或其他容器内的组件）
     *
     * @param designForm
     * @param callback   需要自实现的回调函数
     */
    public static JSONArray recursiveAllWidget(DesignForm designForm, IDesformRecursive callback) {
        JSONObject json = JSON.parseObject(designForm.getDesformDesignJson());
        JSONArray dataList = json.getJSONArray("list");
        recursiveAllWidget(dataList, null, callback);
        return dataList;
    }

    /**
     * 递归调用处理所有的组件（包括栅格或其他容器组件内的组件）
     *
     * @param dataList
     * @param callback 需要自实现的回调函数
     */
    public static void recursiveAllWidget(JSONArray dataList, IDesformRecursive callback) {
        recursiveAllWidget(dataList, null, callback);
    }

    /**
     * 递归调用处理所有的组件（包括栅格或其他容器组件内的组件）
     *
     * @param array
     * @param parent
     * @param callback 需要自实现的回调函数
     */
    public static void recursiveAllWidget(JSONArray array, JSONObject parent, IDesformRecursive callback) {
        for (int i = 0; i < array.size(); i++) {
            JSONObject item = array.getJSONObject(i);
            WidgetTypes type = WidgetTypes.getByValue(item.getString("type"));
            // 判断是否是栅格或其他容器组件
            Boolean isContainer = item.getBoolean("isContainer");
            if (isContainer != null && isContainer) {
                if (item.get("columns") != null) {
                    JSONArray columns = item.getJSONArray("columns");
                    for (int j = 0; j < columns.size(); j++) {
                        JSONObject column = columns.getJSONObject(j);
                        recursiveAllWidget(column.getJSONArray("list"), item, callback);
                    }
                } else if (WidgetTypes.CARD == type) {
                    recursiveAllWidget(item.getJSONArray("list"), item, callback);
                } else if (WidgetTypes.TABS == type) {
                    JSONArray panes = item.getJSONArray("panes");
                    for (int j = 0; j < panes.size(); j++) {
                        JSONObject pane = panes.getJSONObject(j);
                        recursiveAllWidget(pane.getJSONArray("list"), item, callback);
                    }
                }
            }
            // 执行回调函数
            if (callback != null) {
                callback.execute(type, item, parent);
            }
        }
    }

    /**
     * 获取设计JSON
     */
    public static JSONObject getDesformJSON(DesignForm designForm) {
        return JSON.parseObject(designForm.getDesformDesignJson());
    }

    public static JSONArray getDataList(DesignForm designForm) {
        return getDataList(getDesformJSON(designForm));
    }

    /**
     * 获取设计JSON的list
     */
    public static JSONArray getDataList(JSONObject desformJSON) {
        return desformJSON.getJSONArray("list");
    }

    public static JSONObject getConfig(DesignForm designForm) {
        return getConfig(getDesformJSON(designForm));
    }

    /**
     * 获取设计JSON的config
     */
    public static JSONObject getConfig(JSONObject desformJSON) {
        return desformJSON.getJSONObject("config");
    }

    /**
     * 将 desform 转换成 ExcelExportEntity
     *
     * @param designForm
     * @return
     */
    public static List<ExcelExportEntity> convertToExportEntity(DesignForm designForm) {
        ISysBaseAPI sysBaseAPI = SpringContextUtils.getBean(ISysBaseAPI.class);
        JSONArray dataList = getDataList(designForm);
        List<ExcelExportEntity> entityList = new ArrayList<>();
        recursiveAllWidget(dataList, (type, item, parent) -> {
            // 过滤掉不导出的组件
            if (!isNotDataWidget(type)) {
                ExcelExportEntity entity = new ExcelExportEntity(item.getString("name"), item.get("model"));
                entity.setWidth(30);
                JSONObject options = item.getJSONObject("options");
                if (options != null) {
                    // 处理字典
                    String dictCode = options.getString("dictCode");
                    if (StringUtils.isNotBlank(dictCode)) {
                        List<DictModel> dictList = sysBaseAPI.queryDictItemsByCode(dictCode);
                        String[] dictReplaces = dictList.stream().map(d -> d.getText() + "_" + d.getValue()).toArray(String[]::new);
                        entity.setReplace(dictReplaces);
                    }
                }
                entityList.add(entity);
            }
        });
        return entityList;
    }

    /**
     * 将 widgetList 转换成 ExcelExportEntity
     *
     * @param widgetList
     * @return
     */
    public static List<ExcelExportEntity> convertToExportEntity(List<DesformWidget> widgetList) {
        ISysBaseAPI sysBaseAPI = SpringContextUtils.getBean(ISysBaseAPI.class);
        List<ExcelExportEntity> entityList = new ArrayList<>();
        for (DesformWidget widget : widgetList) {
            ExcelExportEntity entity = new ExcelExportEntity(widget.getName(), widget.getModel());
            entity.setWidth(30);
            DesformOptions options = widget.getOptions();
            if (options != null) {
                // 处理字典
                String dictCode = options.getDictCode();
                if (StringUtils.isNotBlank(dictCode)) {
                    List<DictModel> dictList = sysBaseAPI.queryDictItemsByCode(dictCode);
                    String[] dictReplaces = dictList.stream().map(d -> d.getText() + "_" + d.getValue()).toArray(String[]::new);
                    entity.setReplace(dictReplaces);
                }
            }
            entityList.add(entity);
        }
        return entityList;
    }

    /**
     * 判断给定的组件是否不是数据组件，即仅供展示不存储数据的组件
     */
    public static boolean isNotDataWidget(WidgetTypes type) {
        if (type == null) {
            return false;
        }
        switch (type) {
            case GRID:
            case CARD:
            case TABS:
            case TEXT:
            case BLANK:
            case BUTTON:
            case BUTTONS:
            case DIVIDER:
            case SUB_TABLE_DESIGN:
                return true;
            default:
                return false;
        }
    }


    // 外部模拟登陆临时账号密码
    private static final String EXTERNAL_USERNAME = "_reserve_user_external";
    private static final String EXTERNAL_PASSWORD = "jeecg@123";

    /**
     * 模拟登陆接口，获取模拟 Token
     *
     * @return
     */
    public static String getMockToken() {
        RedisUtil redisUtil = SpringContextUtils.getBean(RedisUtil.class);
        // 生成token
        String token = JwtUtil.sign(EXTERNAL_USERNAME, EXTERNAL_PASSWORD);
        // 设置 token 缓存，有效时间为 30 分钟
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, 30 * 60 * 1000);
        return token;
    }

    /**
     * 异步执行方法
     */
    public static Thread asyncMethod(Runnable target) {
        Thread t = new Thread(target);
        try {
            t.start();
        } catch (Exception e) {
            log.error("异步方法执行失败：" + e.getMessage());
        }
        return t;
    }

    /**
     * 获取 JeecgElasticsearchTemplate 实例
     *
     * @return
     */
    public static JeecgElasticsearchTemplate getJes() {
        return SpringContextUtils.getBean(JeecgElasticsearchTemplate.class);
    }

    /**
     * 异步创建 ElasticSearch 索引
     *
     * @param desformCode
     */
    public static void asyncCreateEsIndex(String desformCode) {
        asyncMethod(() -> {
            try {
                getJes().createIndex(desformCode);
            } catch (Exception e) {
                log.warn("ES索引创建失败：" + e.getMessage());
            }
        });
    }

    /**
     * 异步删除 ElasticSearch 索引
     *
     * @param desformCode
     */
    public static void asyncRemoveEsIndex(String desformCode) {
        asyncMethod(() -> {
            try {
                getJes().removeIndex(desformCode);
            } catch (Exception e) {
                log.warn("ES索引删除失败：" + e.getMessage());
            }
        });
    }

    /**
     * 异步保存或更新 ElasticSearch 索引数据
     *
     * @param desformCode
     * @param data
     */
    public static void asyncSaveOrUpdateEsIndex(String desformCode, DesignFormData data) {
        asyncMethod(() -> {
            try {
                log.info("异步保存或更新 ElasticSearch 索引数据，desformCode= " + desformCode + "，designFormData= " + data.toString());
                getJes().saveOrUpdate(desformCode, "design_form", data.getId(), JSON.parseObject(data.getDesformDataJson()));
            } catch (Exception e) {
                log.warn("ES索引数据保存失败：" + e.getMessage());
            }
        });
    }

    /**
     * 异步删除 ElasticSearch 索引数据
     *
     * @param desformCode
     * @param data
     */
    public static void asyncDeleteEsIndex(String desformCode, DesignFormData data) {
        asyncMethod(() -> {
            try {
                getJes().delete(desformCode, "design_form", data.getId());
            } catch (Exception e) {
                log.warn("ES索引数据删除失败：" + e.getMessage());
            }
        });
    }

    /**
     * 获取所有需要转换的组件的转换器，map的key是组件的modal，value是转换器方法
     *
     * @return
     */
    public static Map<String, ConvertItem> getConvertersIfNeed(JSONArray dataList) {
        Map<String, ConvertItem> converters = new HashMap<>();
        recursiveAllWidget(dataList, (type, item, parent) -> {
            String model = item.getString("model");
            ConvertItem convertItem = new ConvertItem(model, item);
            // 判断类型是否需要转换
            if (WidgetTypes.DATE == type) {
                convertItem.setConverter(DesformConverter::formatDate);
            } else if (WidgetTypes.TIME == type) {
                convertItem.setConverter(DesformConverter::formatTime);
            } else if (WidgetTypes.NUMBER == type) {
                convertItem.setConverter(DesformConverter::formatNumber);
            }
            // 需要转换的放进转转换器Map里
            if (convertItem.getConverter() != null) {
                converters.put(model, convertItem);
            }
        });
        return converters;
    }

    /**
     * 通过实体获取组件列表（包括主表和子表）
     */
    public static DesformWidgetList getDesformWidgetListByEntity(DesignForm designForm) {
        if (designForm == null) {
            return null;
        }
        String desJSON = designForm.getDesformDesignJson();
        if (StringUtils.isBlank(desJSON)) {
            return null;
        }
        JSONObject desformJSON = JSON.parseObject(desJSON);
        JSONArray dataList = desformJSON.getJSONArray("list");
        return DesformUtils.getDesformWidgetListByDataList(dataList);
    }

    /**
     * 通过实体获取组件列表（包括主表和子表）
     *
     * @return DesformWidgetList
     */
    public static DesformWidgetList getDesformWidgetListByDataList(JSONArray dataList) {
        if (dataList == null) {
            return null;
        }
        DesformWidgetList widgetList = new DesformWidgetList();

        recursiveAllWidget(dataList, (type, item, parent) -> {
            DesformWidget widget = item.toJavaObject(DesformWidget.class);
            // 过滤掉不导出的组件
            if (!isNotDataWidget(type)) {
                widget.setType(type);
                if (parent != null && WidgetTypes.SUB_TABLE_DESIGN.compare(parent.getString("type"))) {
                    // 存储子表字段
                    String subModel = parent.getString("model");
                    widgetList.sub.computeIfAbsent(subModel, v -> new ArrayList<>()).add(widget);
                    // 存储子表的显示名
                    widgetList.subNames.computeIfAbsent(subModel, v -> parent.getString("name"));
                } else {
                    widgetList.main.add(widget);
                }
            }
        });
        return widgetList;
    }

}